using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Framework.Core;
namespace Framework
{
    public class AtlasLoader
    {
        private readonly AssetLoader _loader;
        private readonly CustomPool<LoadItem> _loadPool;
        private readonly Dictionary<int, LoadItem> _loadMap;
        public AtlasLoader(AssetLoader loader)
        {
            _loader = loader;
            _loadPool = new CustomPool<LoadItem>(() => { return new LoadItem(); }, 30);
            _loadMap = new Dictionary<int, LoadItem>();
        }
        public void Update(float deltaTime, float unscaledDeltaTime)
        {

        }
        public void SetSprite(Image target, string spritePath, bool nativeSize = false, bool autoActive = false)
        {
            if (target == null) return;
            var instanceId = target.GetInstanceID();
            if (!_loadMap.TryGetValue(instanceId, out LoadItem load))
            {
                load = _loadPool.Get();
                load.SetLoader(_loader, onDestory);
                _loadMap.Add(instanceId, load);
                load.InstanceId = instanceId;
                load.SetTarget(target);
            }
            load.NativeSize = nativeSize;
            load.AutoActive = autoActive;
            load.Load(spritePath);
        }
        public void SetSprite(SpriteRenderer target, string spritePath, bool autoActive = false)
        {
            if (target == null) return;
            var instanceId = target.GetInstanceID();
            if (!_loadMap.TryGetValue(instanceId, out LoadItem load))
            {
                load = _loadPool.Get();
                load.SetLoader(_loader, onDestory);
                _loadMap.Add(instanceId, load);
                load.InstanceId = instanceId;
                load.SetTarget(target);
            }
            load.AutoActive = autoActive;
            load.Load(spritePath);
        }
        private void onDestory(LoadItem value)
        {
            _loadMap.Remove(value.InstanceId);
            _loadPool.Release(value);
            value.Clear();
        }

    }
    internal class LoadItem
    {
        public int InstanceId;
        public Image TargetImage;
        public SpriteRenderer TargetSpriteRenderer;
        public string AssetPath { get; private set; }
        public bool NativeSize;
        public bool AutoActive;
        private AssetLoader _loader;
        private bool _loading;
        private int _changedCount;
        private Action<LoadItem> destroyHandler;
        private IAssetResult unloadToken;
        public void SetLoader(AssetLoader loader, Action<LoadItem> destroyCallback)
        {
            _loader = loader;
            _loading = false;
            _changedCount = 0;
            this.destroyHandler = destroyCallback;
        }

        public void SetTarget(Image value)
        {
            this.TargetImage = value;
            var unload = value.gameObject.AddComponent<DestroyWatcher>();
            unload.Callback = onDestory;
        }
        public void SetTarget(SpriteRenderer value)
        {
            this.TargetSpriteRenderer = value;
            var unload = value.gameObject.AddComponent<DestroyWatcher>();
            unload.Callback = onDestory;
        }
        public void Load(string path)
        {
            if (unloadToken != null)
            {
                if (unloadToken.Path != path)
                {
                    _loader.Unload(unloadToken);
                    unloadToken = null;
                }
            }
            AssetPath = path;
            if (unloadToken != null)
            {
                loaded();
                return;
            }
            if (_loading) return;
            _loading = true;
            _loader.LoadAsset(AssetPath, Loaded);
        }
        public void Clear()
        {
            if (unloadToken != null)
            {
                _loader.Unload(unloadToken);
                unloadToken = null;
            }
            _loader = null;
            TargetImage = null;
            TargetSpriteRenderer = null;
            _loading = false;
            AssetPath = null;
            NativeSize = false;
            AutoActive = false;
            _changedCount = 0;
            destroyHandler = null;
        }
        private void onDestory(DestroyWatcher item)
        {
            destroyHandler?.Invoke(this);
        }
        private void Loaded(IAssetResult result)
        {
            unloadToken = result;
            if (unloadToken.Asset == null)
            {
                _loading = false;
                return;
            }
            if (unloadToken.Path != AssetPath)
            {
                _changedCount++;
                if (_changedCount < 3)
                {
                    _loader.Unload(unloadToken);
                    _loader.LoadAsset(AssetPath, Loaded);
                    FrameworkLog.LogErrorFormat("Sprite Path {0} change to {1}", unloadToken.Path, AssetPath);
                    unloadToken = null;
                }
                return;
            }
            _loading = false;
            loaded();
        }
        private void loaded()
        {
            if (unloadToken.Asset is Sprite sprite)
            {
                setup(sprite);
            }
            else if (unloadToken.Asset is Texture2D texture2D)
            {
                //编辑器模式可能执行到这里
                setup(Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f)));
            }

        }
        private void setup(Sprite value)
        {
            if (TargetImage != null)
            {
                TargetImage.sprite = value;
                if (AutoActive)
                {
                    if (!TargetImage.gameObject.activeSelf)
                    {
                        TargetImage.gameObject.SetActive(true);
                    }
                }
                if (NativeSize)
                {
                    TargetImage.SetNativeSize();
                }
            }
            else if (TargetSpriteRenderer != null)
            {
                TargetSpriteRenderer.sprite = value;
                if (AutoActive)
                {
                    if (!TargetSpriteRenderer.gameObject.activeSelf)
                    {
                        TargetSpriteRenderer.gameObject.SetActive(true);
                    }
                }
            }
        }
    }
}